package com.dc.commons.config.web;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;

import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterRegistration;
import javax.servlet.ServletContext;

import org.springframework.util.ObjectUtils;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

import com.dc.commons.config.web.context.ContextLoaderListenerWrapper;
import com.dc.commons.config.web.context.DcContextLoaderListener;

/*******************************************************************************<P>
 * 文件名: AbstraceWebInitializer.java <br>
 * 版本: 1.0<br>
 * 描述: WebInitializer 扩展 <br>
 * 版权所有: <br>
 * <P>
 * 创建者: 王建栋 <br>
 * 创建日期: 2015年12月16日 下午3:42:36<br>
 * 修改者: <br>
 * 修改日期: <br>
 * 修改说明: <br>
 *****************************************************************************
 */
public abstract class AbstraceWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

	
	protected abstract String[] getRootConfigLocations();

	
	protected abstract String[] getServletConfigLocations();
	
	protected abstract ContextLoaderListenerWrapper getContextLoaderListenerWrapper();
	

	/**
	 * 扩展  RootApplicationContext
	 */
	@Override
	protected WebApplicationContext createRootApplicationContext() {
		Class<?>[] configClasses = getRootConfigClasses();
		if (!ObjectUtils.isEmpty(configClasses)) {
			AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
			rootAppContext.register(configClasses);
			if(!ObjectUtils.isEmpty(getRootConfigLocations())){
				rootAppContext.setConfigLocations(getRootConfigLocations());
			}
			rootAppContext.getEnvironment().setActiveProfiles("testing");
			return rootAppContext;
		}
		else {
			return null;
		}
	}
	
	/**
	 * 扩展 ServletApplicationContext
	 */
	@Override
	protected WebApplicationContext createServletApplicationContext() {
		AnnotationConfigWebApplicationContext servletAppContext = new AnnotationConfigWebApplicationContext();
		Class<?>[] configClasses = getServletConfigClasses();
		if (!ObjectUtils.isEmpty(configClasses)) {
			servletAppContext.register(configClasses);
		}
		if(!ObjectUtils.isEmpty(getServletConfigLocations())){
			servletAppContext.setConfigLocations(getServletConfigLocations());
		}
		return servletAppContext;
	}

	/**
	 * 扩展监听类 添加监听包装
	 */
	@Override
	protected void registerContextLoaderListener(ServletContext servletContext) {
		
		WebApplicationContext rootAppContext = createRootApplicationContext();
		if (rootAppContext != null) {
			DcContextLoaderListener listener = new DcContextLoaderListener(rootAppContext,getContextLoaderListenerWrapper());
			listener.setContextInitializers(getRootApplicationContextInitializers());
			servletContext.addListener(listener);
		}
		else {
			logger.debug("No ContextLoaderListener registered, as " +
					"createRootApplicationContext() did not return an application context");
		}
	}
	
	protected EnumSet<DispatcherType> getDispatcherTypes() {
		return (isAsyncSupported() ?
				EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.ASYNC) :
				EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.INCLUDE));
	}
	
	/**
	 *  字符编码过滤器
	 */
	@Override
	protected Filter[] getServletFilters() {
		List<Filter> list=new ArrayList<Filter>();
		CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
        characterEncodingFilter.setEncoding("UTF-8");
        characterEncodingFilter.setForceEncoding(true);
        list.add(characterEncodingFilter);
		return list.toArray(new Filter[]{});
	}
	
	/**
	 * Shiro 过滤器
	 * @param servletContext
	 */
	protected void addShiroFilter(ServletContext servletContext){
		/**
		 * shiro Filter
		 */
		DelegatingFilterProxy shiroFilterProxy=new DelegatingFilterProxy();
        shiroFilterProxy.setBeanName("shiroFilter");
        shiroFilterProxy.setTargetFilterLifecycle(true);
        FilterRegistration filterRegistration =
        		servletContext.addFilter("shiroFilter", shiroFilterProxy);
        
        /**
         * shiro 映射 扩展
         */
        String[] servletMapping=getServletMappings();
        String[] shiroExtendsMapping=getShiroExtendsMapping();
        String[] shiroMapping=servletMapping;
        if(shiroExtendsMapping!=null&&shiroExtendsMapping.length>0){
        	shiroMapping=new String[servletMapping.length+shiroExtendsMapping.length];
        	System.arraycopy(servletMapping, 0,shiroMapping, 0, servletMapping.length);
        	System.arraycopy(shiroExtendsMapping, 0,shiroMapping, servletMapping.length, shiroExtendsMapping.length);
        	
        }
        
        filterRegistration.addMappingForUrlPatterns(getDispatcherTypes(), false,shiroMapping);
	}
	
	/**
	 * shiro 在 servlet Mapping 的基础上扩展其他的过滤
	 * @return ShiroExtendsMapping
	 */
	public abstract String[] getShiroExtendsMapping();
	
}
